﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Xml.Xsl;

namespace Ekomunikacia
{
    public partial class Form1 : Form
    {
        #region private global variables

        private static bool _isValid = true;
        private static string _message = string.Empty;

        #endregion

        public Form1()
        {
            InitializeComponent();
        }
        
        #region help methods

        /// <summary>
        /// Clean field date of birth on click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtDateOfBirth_Click(object sender, EventArgs e)
        {
            this.txtDateOfBirth.Text = string.Empty;
        }

        /// <summary>
        /// Refresh dataGrid
        /// </summary>
        private void RefreshDataGridView()
        {
            DataSet ds = new DataSet();
            DataViewManager dsView;

            if (this.checkBox1.Checked)
            {
                ds.ReadXml("sample.xml");
            }
            else
            {
                ds.ReadXml("tmp.xml");
            }

            dsView = ds.DefaultViewManager;
            this.dataGridView1.DataSource = dsView;
            this.dataGridView1.DataMember = "Person";
        }

        /// <summary>
        /// Add to xml new record
        /// </summary>
        /// <param name="name">Name</param>
        /// <param name="surname">Surname</param>
        /// <param name="sDataOfBirth">Date of birth - format: YYYY-MM-DD</param>
        /// <param name="streetType">trvala / prechodna - value from combobox</param>
        /// <param name="streetName">Name of street</param>
        /// <param name="streetNumber">Number of street</param>
        /// <param name="zip">ZIP</param>
        /// <param name="city">City</param>
        /// <param name="onlyAddress">true/false - if you want to add only address to the existing record</param>
        /// <returns></returns>
        private XmlDocument AddRecordToXml(string name, string surname, string sDataOfBirth, string streetType, string streetName, string streetNumber, string zip, string city, bool onlyAddress)
        {
            XmlDocument xmlDoc = new XmlDocument();
            XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
            XmlNamespaceManager ns = new XmlNamespaceManager(xmlDoc.NameTable);
            ns.AddNamespace("my", "http://tempuri.org/myXsdSchema.xsd");
            int maxId = 0;

            if (!File.Exists("tmp.xml"))
            {
                this.toolStripStatusLabel1.Text = "Vytváram XML";
                xmlDoc.LoadXml("<Contacts xmlns=\"http://tempuri.org/myXsdSchema.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://tempuri.org/myXsdSchema.xsd file:/D:/Skola/5.%20rocnik/2.%20semester/eKom/Ekomunikacia/Ekomunikacia/myXsdSchema.xsd\" />");
                xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement);
                xmlDoc.Save("tmp.xml");
                this.toolStripStatusLabel1.Text = "Xml vytvorené";
            }

            this.toolStripStatusLabel1.Text = "Načítavam aktuálne XML";

            if (this.checkBox1.Checked)
            {
                xmlDoc.Load("sample.xml");
            }
            else
            {
                xmlDoc.Load("tmp.xml");
            }

            //zober maxID + 1 : nove id OSOBY
            try
            {
                XmlNode lastOfPerson = xmlDoc.DocumentElement.LastChild.SelectSingleNode("my:Id", ns);
                maxId = Convert.ToInt32(lastOfPerson.InnerText) + 1;
            }
            catch
            {
                maxId = 0;
            }

            if (!onlyAddress)
            {
                ///Pridanie osoby
                ///najprv zistim, ci nahodou dana osoba uz nie je vytvorena
                ///ak ano, tak vypisem hlasku, ci si je pouzivatel isty, ze chce pridat osobu s rovnakymi parametrami

                XmlNodeList listPersons = xmlDoc.GetElementsByTagName("Person", "http://tempuri.org/myXsdSchema.xsd");
                foreach (XmlNode node in listPersons)
                {
                    try
                    {
                        //skusim najst ci existuje - parametre: meno, priezvisko, datum narodenia
                        if ((node.SelectSingleNode("my:Name", ns).InnerText == name) && (node.SelectSingleNode("my:Surname", ns).InnerText == surname) && (node.SelectSingleNode("my:DateOfBirth", ns).InnerText == sDataOfBirth))
                        {
                            DialogResult result = MessageBox.Show("Dana osoba uz existuje, zelate si pridat osobu do adresara aj napriek tomu?", "Pozor!", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button2);

                            if (result == System.Windows.Forms.DialogResult.No)
                            {
                                return null;
                            }
                            else
                                break; //ak ano, tak proste budem pokracovat
                        }
                    }
                    catch
                    {
                        //tu by sme teoreticky ani nemuseli dostat, takze tento try-catch tu ani nemusi byt, iba zeby sa sprasilo xmlko vonkajsim zasahom
                    }
                }

                //vytvorenie elementov
                XmlElement root = xmlDoc.DocumentElement;
                XmlElement person = xmlDoc.CreateElement("Person", "http://tempuri.org/myXsdSchema.xsd");
                XmlElement address = xmlDoc.CreateElement("Address", "http://tempuri.org/myXsdSchema.xsd");


                XmlElement xmlId = xmlDoc.CreateElement("Id", "http://tempuri.org/myXsdSchema.xsd");
                xmlId.InnerText = maxId.ToString();
                XmlElement xmlName = xmlDoc.CreateElement("Name", "http://tempuri.org/myXsdSchema.xsd");
                xmlName.InnerText = name;
                XmlElement xmlSurname = xmlDoc.CreateElement("Surname", "http://tempuri.org/myXsdSchema.xsd");
                xmlSurname.InnerText = surname;
                XmlElement xmlDateOfBirth = xmlDoc.CreateElement("DateOfBirth", "http://tempuri.org/myXsdSchema.xsd");
                xmlDateOfBirth.InnerText = sDataOfBirth;
                XmlElement xmlStreetType = xmlDoc.CreateElement("Type", "http://tempuri.org/myXsdSchema.xsd");
                xmlStreetType.InnerText = streetType;
                XmlElement xmlStreetName = xmlDoc.CreateElement("StreetName", "http://tempuri.org/myXsdSchema.xsd");
                xmlStreetName.InnerText = streetName;
                XmlElement xmlStreetNumber = xmlDoc.CreateElement("StreetNumber", "http://tempuri.org/myXsdSchema.xsd");
                xmlStreetNumber.InnerText = streetNumber;
                XmlElement xmlZip = xmlDoc.CreateElement("Zip", "http://tempuri.org/myXsdSchema.xsd");
                xmlZip.InnerText = zip;
                XmlElement xmlCity = xmlDoc.CreateElement("City", "http://tempuri.org/myXsdSchema.xsd");
                xmlCity.InnerText = city;

                //pridanie ich na spravne miesto
                address.AppendChild(xmlStreetType);
                address.AppendChild(xmlStreetName);
                address.AppendChild(xmlStreetNumber);
                address.AppendChild(xmlZip);
                address.AppendChild(xmlCity);

                person.AppendChild(xmlId);
                person.AppendChild(xmlName);
                person.AppendChild(xmlSurname);
                person.AppendChild(xmlDateOfBirth);
                person.AppendChild(address);

                root.AppendChild(person);

                xmlDoc.Save("tmp.xml");
            }
            else
            {
                if (xmlDoc.GetElementsByTagName("Person").Count > 0)
                {
                    XmlElement address = xmlDoc.CreateElement("Address", "http://tempuri.org/myXsdSchema.xsd");

                    XmlElement xmlStreetType = xmlDoc.CreateElement("Type", "http://tempuri.org/myXsdSchema.xsd");
                    xmlStreetType.InnerText = streetType;
                    XmlElement xmlStreetName = xmlDoc.CreateElement("StreetName", "http://tempuri.org/myXsdSchema.xsd");
                    xmlStreetName.InnerText = streetName;
                    XmlElement xmlStreetNumber = xmlDoc.CreateElement("StreetNumber", "http://tempuri.org/myXsdSchema.xsd");
                    xmlStreetNumber.InnerText = streetNumber;
                    XmlElement xmlZip = xmlDoc.CreateElement("Zip", "http://tempuri.org/myXsdSchema.xsd");
                    xmlZip.InnerText = zip;
                    XmlElement xmlCity = xmlDoc.CreateElement("City", "http://tempuri.org/myXsdSchema.xsd");
                    xmlCity.InnerText = city;

                    //pridanie ich na spravne miesto
                    address.AppendChild(xmlStreetType);
                    address.AppendChild(xmlStreetName);
                    address.AppendChild(xmlStreetNumber);
                    address.AppendChild(xmlZip);
                    address.AppendChild(xmlCity);                    

                    XmlNodeList listPersons = xmlDoc.GetElementsByTagName("Person", "http://tempuri.org/myXsdSchema.xsd");

                    int pocetNodov = listPersons.Count;
                    foreach (XmlNode node in listPersons)
                    {
                        pocetNodov--;
                        try
                        {
                            if ((node.SelectSingleNode("my:Name", ns).InnerText == name) && (node.SelectSingleNode("my:Surname", ns).InnerText == surname) && (node.SelectSingleNode("my:DateOfBirth", ns).InnerText == sDataOfBirth))
                            {
                                node.AppendChild(address);
                                xmlDoc.Save("tmp.xml");
                            }
                            else
                            {
                                if (pocetNodov > 0)
                                    continue;
                                DialogResult result = MessageBox.Show("Dana osoba este neexistuje, zelate si pridat osobu do adresara?", "Pozor!", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
                                                                
                                if (result == System.Windows.Forms.DialogResult.Yes)
                                {
                                    //volaj este raz rovnaku funkciu a po odovzdani xml vyskoc - rekurzia
                                    xmlDoc = AddRecordToXml(name, surname, sDataOfBirth, streetType, streetName, streetNumber, zip, city, false);
                                    return xmlDoc;
                                }
                                else if (result == System.Windows.Forms.DialogResult.No)
                                {
                                    return null;
                                }
                            }
                        }
                        catch
                        {
                            DialogResult result = MessageBox.Show("Este neexistuje ziadna osoba", "Pozor!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                            if (result == System.Windows.Forms.DialogResult.OK)
                            {
                                return null;
                            }
                        }
                    }
                }
                else
                {
                    DialogResult result = MessageBox.Show("Nie je mozne pridat adresu, vytvorte najprv osobu!", "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
                    if (result == System.Windows.Forms.DialogResult.OK)
                    {
                        return null;
                    }
                }
            }

            return xmlDoc;
        }

        //toto by sa malo spustit len vtedy, ak je dokument nevalidny
        private static void MyValidationEventHandler(object sender, ValidationEventArgs args)
        {
            _isValid = false;
            _message = args.Message;
        }

        #endregion

        #region buttonClick

        /// <summary>
        /// Add new recod
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            XmlDocument xmlDoc = new XmlDocument();
            
            //pridam do xmlka
            xmlDoc = AddRecordToXml(this.txtName.Text, this.txtSurname.Text, this.txtDateOfBirth.Text, this.cbAddressType.SelectedItem.ToString(), this.txtStreetName.Text, this.txtStreetNumber.Text, this.txtZip.Text, this.txtCity.Text, false);

            if(xmlDoc != null)
                RefreshDataGridView();

            this.button2.Enabled = true;

            this.toolStripStatusLabel1.Text = "Aktuálne XML načítané";
        }

        /// <summary>
        /// Refresh datagrid
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                textBox1.Text = string.Empty;
                RefreshDataGridView();
            }
            catch
            {
                //len kvoli tomu, aby sa nerefreshovalo, kde je xmlko prazdne, alebo ak neexistuje
            }
        }

        /// <summary>
        /// Add new address to the exist record
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            XmlDocument xmlDoc = new XmlDocument();

            //pridam do xmlka
            xmlDoc = AddRecordToXml(this.txtName.Text, this.txtSurname.Text, this.txtDateOfBirth.Text, this.cbAddressType.SelectedItem.ToString(), this.txtStreetName.Text, this.txtStreetNumber.Text, this.txtZip.Text, this.txtCity.Text, true);

            if(xmlDoc != null)
                RefreshDataGridView();

            this.button2.Enabled = true;

            this.toolStripStatusLabel1.Text = "Aktuálne XML načítané";
        }
        
        /// <summary>
        /// Validation XML
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            _isValid = true;
            _message = string.Empty;
            XmlTextReader r = new XmlTextReader("tmp.xml");
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.Schemas.Add("http://tempuri.org/myXsdSchema.xsd", @"myXsdSchema.xsd");
            
            //nastavim typ
            settings.ValidationType = ValidationType.Schema;
            
            //pridam handler
            settings.ValidationEventHandler += new ValidationEventHandler(MyValidationEventHandler);

            XmlReader reader = XmlReader.Create(r, settings);

            while (reader.Read())
            {
                //tu moze byt cokolvek, ak treba
            }
            reader.Close();

            if (_isValid)
                textBox1.Text = "Dokument je validny";
            else
                textBox1.Text = "Dokument je nevalidny, obsahuje chyby: \r\n\r\n" + _message;
        }

        /// <summary>
        /// Deleting rows
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataGridView1_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            XmlDocument document = new XmlDocument();
            document.Load("tmp.xml");
            
            //id zaznamu
            string id = dataGridView1.SelectedRows[0].Cells[0].Value.ToString();
            
            XmlNamespaceManager ns = new XmlNamespaceManager(document.NameTable);
            ns.AddNamespace("my", "http://tempuri.org/myXsdSchema.xsd");

            XPathNodeIterator nodesToCheck = document.CreateNavigator().Select("my:Contacts/my:Person/my:Id", ns);
            List<XPathNavigator> nodesToDelete = new List<XPathNavigator>();
            foreach (XPathNavigator currentItem in nodesToCheck)
                if (currentItem.Value == id.ToString())
                {
                    currentItem.MoveToParent();
                    nodesToDelete.Add(currentItem);
                }

            foreach (XPathNavigator deleteMe in nodesToDelete)
                deleteMe.DeleteSelf();

            document.Save("tmp.xml");            
        }
        
        /// <summary>
        /// XSL Transform
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button5_Click(object sender, EventArgs e)
        {
            XPathDocument myXPathDoc;
            XslTransform myXslTrans = new XslTransform();

            try
            {
                if (_isValid)
                {
                    myXPathDoc = new XPathDocument("tmp.xml");
                    myXslTrans.Load("myXslTransform.xsl");

                    MemoryStream ms = new MemoryStream();
                    //treamWriter sw = new StreamWriter(s);

                    myXslTrans.Transform(myXPathDoc, null, ms);
                    
                    ms.Seek(0, SeekOrigin.Begin);
                    
                    StreamReader sr = new StreamReader(ms);
                    
                    textBox1.Text = sr.ReadToEnd();
                }
                else
                {
                    textBox1.Text = "Dokument je nevalidny, obsahuje chyby: \r\n\r\n" + _message;
                }
            }
            catch (Exception ex)
            {
                DialogResult result = MessageBox.Show("Chyba: \r\n" + ex.ToString(), "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
            }
        }
                
        /// <summary>
        /// xml export
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button6_Click(object sender, EventArgs e)
        {
            XmlDocument xmlDoc = new XmlDocument();

            try
            {
                xmlDoc.Load("tmp.xml");
            }
            catch
            {
                DialogResult result = MessageBox.Show("XML este nie je mozne exportovat, najprv vytvorte nejake zaznamy!", "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
            }

            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Filter = "Xml file|*.xml";
            saveFileDialog1.Title = "Uložiť XML";
            saveFileDialog1.RestoreDirectory = true;

            if(saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                xmlDoc.Save(saveFileDialog1.FileName);
            }         
        }

        /// <summary>
        /// podpis xmlka
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button7_Click(object sender, EventArgs e)
        {
            string err = string.Empty;
            Sign signXml = new Sign();

            OpenFileDialog oFile = new OpenFileDialog();
            oFile.Filter = "Xml file|*.xml";
            oFile.Title = "Vyberte xml súbor na podpísanie";

            if (oFile.ShowDialog() == DialogResult.OK)
            {
                _isValid = true;
                _message = string.Empty;
                XmlTextReader r = new XmlTextReader(oFile.FileName);
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.Schemas.Add("http://tempuri.org/myXsdSchema.xsd", @"myXsdSchema.xsd");

                //nastavim typ
                settings.ValidationType = ValidationType.Schema;

                //pridam handler
                settings.ValidationEventHandler += new ValidationEventHandler(MyValidationEventHandler);

                XmlReader reader = XmlReader.Create(r, settings);

                while (reader.Read())
                {
                    //tu moze byt cokolvek, ak treba
                }
                reader.Close();
                if(_isValid)
                    err = signXml.SignXml("idObjektu", "Xml popis", oFile.FileName, "myXsdSchema.xsd", "http://tempuri.org/myXsdSchema.xsd", "http://www.w3.org/2001/XMLSchema", "myXslTransform.xsl", "http://www.w3.org/1999/XSL/Transform");
                else
                    textBox1.Text = "Dokument je nevalidny, obsahuje chyby: \r\n\r\n" + _message;
            }
            
            if (!String.IsNullOrEmpty(err))
                MessageBox.Show(err, "Chyba!", MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
        }

        #endregion

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// opeciatkuj
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button8_Click(object sender, EventArgs e)
        {
            string err = string.Empty;
            Sign ts = new Sign();

            ts.AddTimeStamp();
        }

        private void button9_Click(object sender, EventArgs e)
        {
            Verify ver = new Verify();
            VerResultStructure result;

            result = ver.VerifyDocument();
            if (result.Result)
                MessageBox.Show("Overenie dokumentu OK", "Valid!", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
            else
                MessageBox.Show("Overenie dokumentu nepreslo! \r\n\r\n" + result.Message, "Not valid!", MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
        }

        
    }
}
